/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package linkedlist;

/**
 *
 * @author Islam Hamdi
 */
public class MyLinkedListS<T> {
private NodeS<T> header;// Pointing to the beginning
	private long size;// size of the list

	/** Default constructor that creates an empty list */
	public MyLinkedListS() {
		size = 0;
		header = new NodeS<T>();
	}

	/** Construct a linkedList with a specified size */
	public MyLinkedListS(int listSize) {
		size = listSize;
		header = new NodeS<T>();
	}

	//
	// /** returns first logical node in the list. */
	// public NodeS<T> getFirstNode() {
	// if (size == 0) {
	// throw new IllegalArgumentException("Empty List!");
	// } else {
	// return header.getNext();
	// }
	// }

	/**
	 * inserts the specified element at the specified position in the list
	 */
	public void add(int index, T element) {
		if (index <= 0 || index > size + 1) {
			throw new IllegalArgumentException("Index Not found !");
		} else {
			NodeS<T> temp = header.getNext();
			NodeS<T> newNode = new NodeS<T>(element);
			if (index == 1) {// if at the beginning of the list
				newNode.setNext(temp);
				header.setNext(newNode);
				temp = null;
			} else {
				NodeS<T> temp1 = temp;
				// tracking nodes till the specified index
				for (int counter = 1; counter < index; counter++) {
					temp1 = temp;
					temp = temp.getNext();
				}
				newNode.setNext(temp);
				temp1.setNext(newNode);
			}
			size++;
		}
	}
        
        /**concatenates two linked list */
        public MyLinkedListS<T> concatenate(MyLinkedListS<T>l2){
            MyLinkedListS<T> temp=new MyLinkedListS<T>();
            temp=this.sublist(1,this.size());
            MyLinkedListS<T> temp1=new MyLinkedListS<T>();
            temp1=l2.sublist(1,l2.size());
            temp.getNode(temp.size()).setNext(temp1.getNode(1));
            temp.setSize(this.size()+l2.size());
            return temp.sublist(1,temp.size());
        }

	/** Inserts the specified element at the end of the list. */
	public void add(T element) {
		add((int) size + 1, element);
		// NodeS<T> end = new NodeS<T>(element);
		// if (size == 0) {
		// header.setNext(end);
		// } else {
		// NodeS<T> tail = getNode((int) size);
		// tail.setNext(end);
		// }
		// size++;
		// NodeS end = new NodeS(element);
		// if (size == 0) {
		// header.setNext(end);
		// } else {
		// NodeS n = header.getNext();
		// NodeS temp = n;
		// while (n != null) {
		// temp = n;
		// n = n.getNext();
		// }
		// temp.setNext(end);
		// }
		// size++;
	}

	/** returns a pointer to the node at the specified index */
	public NodeS<T> getNode(int index) {
		if (index <= 0 || index > size) {
			throw new IllegalArgumentException("Index Out of bounds !");
		} else {
			int counter = 1;
			NodeS<T> temp = header.getNext();
			while (counter != index) {
				temp = temp.getNext();
				counter++;
			}
			return temp;
		}
	}

	/** returns the element at the specified position in the list */
	public T get(int index) {
		return getNode(index).getElement();
		// if (index <= 0 || index > size) {
		// throw new IllegalArgumentException("Index Not found !");
		// } else {
		// int counter = 1;
		// NodeS<T> temp = header.getNext();
		// while (counter != index) {
		// temp = temp.getNext();
		// counter++;
		// }
		// return temp.getElement();
		// }
	}

	/**
	 * replaces the element at the specified position in this list with the
	 * specified element
	 */
	public void set(int index, T element) {
		NodeS<T> temp = getNode(index);
		temp.setElement(element);
	}

	/** removes all of the elements from this list */
	public void clear() {
                size=0;
		header.setNext(null);
	}

	/** returns true if this list contains no elements */
	public boolean isEmpty() {
		if (size == 0) {
			return true;
		} else {
			return false;
		}
	}

	/** removes the element at the specified position in this list */
	public void remove(int index) {
		if (index <= 0 || index > size) {
			throw new IllegalArgumentException("Index not found!");
		} else {
			if (index == 1) {
				header.setNext(null);
			} else {
				NodeS<T> prev = getNode(index - 1);
				NodeS<T> temp = prev.getNext();
				prev.setNext(temp.getNext());
				temp.setNext(null);
				// NodeS temp = header.getNext();
				// NodeS prev = temp;
				// int counter = 1;
				// while (counter != index) {
				// prev = temp;
				// temp = temp.getNext();
				// counter++;
				// }
				// prev.setNext(temp.getNext());
			}
			size--;
		}
	}

        public void setSize(int n){
            size=n;
        }
	/** returns the number of elements in this list */
	public int size() {
		return (int) size;
	}

	/** returns pointer to the header of the list */
	public NodeS<T> getHeader() {
		return header;
	}

	/**
	 * returns a view of the portion of this list between the specified
	 * fromIndex and toIndex, inclusively
	 */
	public MyLinkedListS<T> sublist(int fromIndex, int toIndex) {
		if (fromIndex <= 0 || toIndex > size) {
			throw new IllegalArgumentException("Index Out of bounds !");
		} else {
			MyLinkedListS<T> portion = new MyLinkedListS<T>(toIndex - fromIndex
					+ 1);
			NodeS<T> temp = getNode(fromIndex);
			NodeS<T> first = new NodeS<T>(temp.getElement());
			portion.getHeader().setNext(first);
			NodeS<T> pointer = first;

			for (int i = fromIndex + 1; i <= toIndex; i++) {
				NodeS<T> n = new NodeS<T>(get(i));
				pointer.setNext(n);
				pointer = pointer.getNext();
				// temp = temp.getNext();
			}
			// pointer.setNext(null);
			return portion;
		}
	}

	/**
	 * returns true if this list contains an element that has the same value as
	 * the specified element
	 */
	public boolean contains(T o) {
		boolean status = false;
		if (size == 0) {
			return false;
		} else {
			NodeS<T> temp = header.getNext();
			while (temp != null && !status) {
				if (temp.getElement().equals(o)) {
					status = true;
				}
				temp = temp.getNext();
			}
		}
		return status;
	}

	/**
	 * returns an iterator to enable the multiple traversals on the list
	 * elements
	 */
	public MyLLIteratorS<T> getIterator() {
		return new MyLLIteratorS<T>(this);
	}
}
